using System;
using dnAnalytics.LinearAlgebra;
using dnAnalytics.LinearAlgebra.Solvers;

namespace dnAnalytics.Examples.LinearAlgebra.Solvers
{
    /// <summary>
    /// Provides an example of the use of the BiCGStab iterative solver
    /// </summary>
    public sealed class BicgstabSolverSolve
    {
        /// <summary>
        /// The main method that runs the BiCGStab iterative solver.
        /// </summary>
        public void RunSolver()
        {
            // Create a sparse matrix. For now the size will be 10 x 10 elements
            // The MatrixBuilder.CreateIdentityMatrix() creates a sparse matrix.
            Matrix matrix = MatrixBuilder.CreateIdentityMatrix(10);

            // Create a new convergence monitor. This checks for convergence of the results of the
            // iterative matrix solver.
            // In this case:
            // We perform a maximum of 5000 iterations.
            // We will stop when the residual drops below 1e-14
            // And use the infinity norm as the appropriate norm for the convergence measurement.
            ConvergenceMonitor monitor = new ConvergenceMonitor(5000,
                                                                1e-14,
                                                                matrix.InfinityNorm());

            // Create the solver
            BiConjugateGradientStabilizedSolver solver =
                new BiConjugateGradientStabilizedSolver(matrix, monitor);

            // Create the right hand side vector. The size is the same as the matrix
            // and all values will be 2.0.
            Vector rightHandSideVector = VectorBuilder.CreateVector(10, 2.0, VectorType.Dense);

            // Now that all is set we can solve the matrix equation.
            // If we will only perform a solve once then we can call the
            // solve method like this:
            Vector solutionVector = solver.Solve(rightHandSideVector);

            // Another way to get the values is by using the overloaded solve method
            // In this case the solution vector needs to be of the correct size.
            // This method is more suitable if we need to call the solve method multiple
            // times on the same size matrix and vectors. The reason is that we can now
            // re-use the solution vector which saves CPU cycles during creation and 
            // destruction.
            solver.Solve(rightHandSideVector, solutionVector);
            
            // Finally you can check the reason the solver finished the iterative process
            // by calling the SolutionStatus property on the convergence monitor
            switch(monitor.SolutionStatus)
            {
                case SolutionStatus.None:
                    Console.WriteLine("Oh oh, something went wrong. The iterative process was never started.");
                    break;
                case SolutionStatus.Converged:
                    Console.WriteLine("Yippee, the iterative process converged.");
                    break;
                case SolutionStatus.Diverged:
                    Console.WriteLine("I'm sorry the iterative process diverged.");
                    break;
                case SolutionStatus.IterationBoundsReached:
                    Console.WriteLine("Oh dear, the iterative process ran the maximum number of iterations.");
                    break;
            }
        }
    }
}